﻿using Core.Utility.Attributes;
using Core.Utility.Helper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Core.Utility.Extensions.Json
{
    /// <summary>
    /// 代码-值-描述 特性 - 代码 枚举JsonConverter转换器
    /// </summary>
    public class CodeValueDescriptionAttributeCodeJsonConverter<T> : JsonConverter
    {
        /// <summary>
        /// 
        /// </summary>
        public void EnumConverter()
        {
            //if (!typeof(T).IsEnum)
            //{
            //    throw new ArgumentException("T 必须是枚举类型");
            //}
        }

        /// <summary>
        /// 写入Json
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="objectType"></param>
        /// <param name="existingValue"></param>
        /// <param name="serializer"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
            {
                return null;
            }

            try
            {
                return reader?.Value?.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format($"不能将字段/属性{1}的值{0}转换为Json格式.{Environment.NewLine}{2}", reader.Value, objectType,ex.Message));
            }

        }

        /// <summary>
        /// 判断是否为Bool类型
        /// </summary>
        /// <param name="objectType">类型</param>
        /// <returns>为bool类型则可以进行转换</returns>
        public override bool CanConvert(Type objectType)
        {
            return true;
        }


        public bool IsNullableType(Type t)
        {
            if (t == null)
            {
                throw new ArgumentNullException(nameof(t));
            }

            return t.BaseType != null && (t.BaseType.FullName == "System.ValueType" && t.GetGenericTypeDefinition() == typeof(Nullable<>));
        }

        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
        {
            if (value == null)
            {
                writer.WriteNull();
                return;
            }
            string? bValue = value?.ToString();
            int isNo;
            if (int.TryParse(bValue, out isNo))
            {
                bValue = GetEnumAttrCode(typeof(T), isNo);
            }
            else
            {
                bValue = GetEnumDescription(typeof(T), value?.ToString());
            }


            writer.WriteValue(bValue);
        }

        /// <summary>
        /// 获取枚举描述
        /// </summary>
        /// <param name="type">枚举类型</param>
        /// <param name="value">枚举名称</param>
        /// <returns></returns>
        private string? GetEnumDescription(Type type, string? value)
        {
            try
            {
                if(string.IsNullOrEmpty(value))
                {
                    return "";
                }
                FieldInfo? field = type.GetField(value);
                if (field == null)
                {
                    return "";
                }

                var desc = Attribute.GetCustomAttribute(field, typeof(CodeValueDescriptionAttribute)) as CodeValueDescriptionAttribute;
                if (desc != null) return desc.Code;

                return value;
            }
            catch
            {
                return value;
            }
        }

        /// <summary>
        /// 获取枚举描述
        /// </summary>
        /// <param name="type">枚举类型</param>
        /// <param name="value">枚举hasecode</param>
        /// <returns></returns>
        private string GetEnumAttrCode(Type type, int value)
        {
            try
            {
                FieldInfo? field = type.GetField(Enum.GetName(type, value).GetValueOrDefault());
                if (field == null)
                {
                    return value.ToString();
                }

                var desc = Attribute.GetCustomAttribute(field, typeof(CodeValueDescriptionAttribute)) as CodeValueDescriptionAttribute;
                if (desc != null) return desc.Code;

                return value.ToString();
            }
            catch
            {
                return value.ToString();
            }
        }
    }


    /// <summary>
    /// 代码-值-描述 特性 - 值 枚举JsonConverter转换器
    /// </summary>
    public class CodeValueDescriptionAttributeValueJsonConverter<T> : JsonConverter
    {
        public void EnumConverter()
        {
            //if (!typeof(T).IsEnum)
            //{
            //    throw new ArgumentException("T 必须是枚举类型");
            //}
        }

        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
            {
                return null;
            }

            try
            {
                return reader?.Value?.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format($"不能将字段/属性{1}的值{0}转换为Json格式.{Environment.NewLine}{2}", reader.Value, objectType,ex.Message));
            }

        }

        /// <summary>
        /// 判断是否为Bool类型
        /// </summary>
        /// <param name="objectType">类型</param>
        /// <returns>为bool类型则可以进行转换</returns>
        public override bool CanConvert(Type objectType)
        {
            return true;
        }


        public bool IsNullableType(Type t)
        {
            if (t == null)
            {
                throw new ArgumentNullException(nameof(t));
            }

            return t.BaseType != null && (t.BaseType.FullName == "System.ValueType" && t.GetGenericTypeDefinition() == typeof(Nullable<>));
        }

        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
        {
            if (value == null)
            {
                writer.WriteNull();
                return;
            }
            string? bValue = value?.ToString();
            int isNo;
            if (int.TryParse(bValue, out isNo))
            {
                bValue = GetEnumAttrValue(typeof(T), isNo);
            }
            else
            {
                bValue = GetEnumDescription(typeof(T), value?.ToString());
            }


            writer.WriteValue(bValue);
        }

        /// <summary>
        /// 获取枚举描述
        /// </summary>
        /// <param name="type">枚举类型</param>
        /// <param name="value">枚举名称</param>
        /// <returns></returns>
        private string? GetEnumDescription(Type type, string? value)
        {
            try
            {                
                if(string.IsNullOrEmpty(value))
                {
                    return "";
                }
                FieldInfo? field = type.GetField(value);
                if (field == null)
                {
                    return value;
                }

                var desc = Attribute.GetCustomAttribute(field, typeof(CodeValueDescriptionAttribute)) as CodeValueDescriptionAttribute;
                if (desc != null) return desc.Value;

                return value;
            }
            catch
            {
                return value;
            }
        }

        /// <summary>
        /// 获取枚举描述
        /// </summary>
        /// <param name="type">枚举类型</param>
        /// <param name="value">枚举hasecode</param>
        /// <returns></returns>
        private string GetEnumAttrValue(Type type, int value)
        {
            try
            {
                FieldInfo? field = type.GetField(Enum.GetName(type, value).GetValueOrDefault());
                if (field == null)
                {
                    return value.ToString();
                }

                var desc = Attribute.GetCustomAttribute(field, typeof(CodeValueDescriptionAttribute)) as CodeValueDescriptionAttribute;
                if (desc != null) return desc.Value;

                return value.ToString();
            }
            catch
            {
                return value.ToString();
            }
        }
    }


    /// <summary>
    /// 代码-值-描述 特性 - 描述 枚举JsonConverter转换器
    /// </summary>
    public class CodeValueDescriptionAttributeDescriptionJsonConverter<T> : JsonConverter
    {
        public void EnumConverter()
        {
            //if (!typeof(T).IsEnum)
            //{
            //    throw new ArgumentException("T 必须是枚举类型");
            //}
        }

        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
            {
                return null;
            }

            try
            {
                return reader?.Value?.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format($"不能将字段/属性{1}的值{0}转换为Json格式.{Environment.NewLine}{2}", reader.Value, objectType,ex.Message));
            }

        }

        /// <summary>
        /// 判断是否为Bool类型
        /// </summary>
        /// <param name="objectType">类型</param>
        /// <returns>为bool类型则可以进行转换</returns>
        public override bool CanConvert(Type objectType)
        {
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public bool IsNullableType(Type t)
        {
            if (t == null)
            {
                throw new ArgumentNullException(nameof(t));
            }

            return t.BaseType != null && (t.BaseType.FullName == "System.ValueType" && t.GetGenericTypeDefinition() == typeof(Nullable<>));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="value"></param>
        /// <param name="serializer"></param>
        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
        {
            if (value == null)
            {
                writer.WriteNull();
                return;
            }
            string? bValue = value?.ToString();
            int isNo;
            if (int.TryParse(bValue, out isNo))
            {
                bValue = GetEnumAttrValue(typeof(T), isNo);
            }
            else
            {
                bValue = GetEnumDescription(typeof(T), value?.ToString());
            }


            writer.WriteValue(bValue);
        }

        /// <summary>
        /// 获取枚举描述
        /// </summary>
        /// <param name="type">枚举类型</param>
        /// <param name="value">枚举名称</param>
        /// <returns></returns>
        private string? GetEnumDescription(Type type, string? value)
        {
            try
            {
                if (string.IsNullOrEmpty(value))
                {
                    return "";
                }
                FieldInfo? field = type.GetField(value);
                if (field == null)
                {
                    return value;
                }

                var desc = Attribute.GetCustomAttribute(field, typeof(CodeValueDescriptionAttribute)) as CodeValueDescriptionAttribute;
                if (desc != null) return desc.Description;

                return value;
            }
            catch
            {
                return value;
            }
        }

        /// <summary>
        /// 获取枚举描述
        /// </summary>
        /// <param name="type">枚举类型</param>
        /// <param name="value">枚举hasecode</param>
        /// <returns></returns>
        private string GetEnumAttrValue(Type type, int value)
        {
            try
            {
                FieldInfo? field = type.GetField(Enum.GetName(type, value).GetValueOrDefault());
                if (field == null)
                {
                    return value.ToString();
                }

                var desc = Attribute.GetCustomAttribute(field, typeof(CodeValueDescriptionAttribute)) as CodeValueDescriptionAttribute;
                if (desc != null) return desc.Description;

                return value.ToString();
            }
            catch
            {
                return value.ToString();
            }
        }
    }
}
